package cn.com.open.itembank.service.impl;

import cn.com.open.itembank.common.GlobalConst;
import cn.com.open.itembank.common.enums.ChapterType;
import cn.com.open.itembank.common.enums.Source;
import cn.com.open.itembank.common.enums.SysState;
import cn.com.open.itembank.common.enums.YesOrNo;
import cn.com.open.itembank.dto.CopyCourseModel;
import cn.com.open.itembank.dto.ItemBank;
import cn.com.open.itembank.dto.QuestionCountModel;
import cn.com.open.itembank.dto.ReturnModel;
import cn.com.open.itembank.entity.Chapter;
import cn.com.open.itembank.entity.CourseItemBank;
import cn.com.open.itembank.mapper.CourseItemBankMapper;
import cn.com.open.itembank.redis.RedisConfig;
import cn.com.open.itembank.service.ChapterService;
import cn.com.open.itembank.service.ItemBankQuestionRemoteService;
import cn.com.open.itembank.service.ItemBankService;
import cn.com.open.itembank.service.ItemBankTestPaperRemoteService;
import cn.com.open.itembank.utils.DateUtil;
import cn.com.open.itembank.utils.StringUtil;
import cn.com.open.itembank.utils.UUIDUtil;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * Created by lucky on 2017/7/17.
 */
@Service("itemBankService")
public class ItemBankServiceImpl implements ItemBankService {
    /**
     * 配置文件中的删除题库的appKey许可列表
     */
    @Value("${app.itembank.permissionAppIds}")
    private String permissionList;

    @Value("${course.questioncount.key}")
    private String courseQuestionCountKey;

    @Value("${course.questioncount.redis.expire}")
    private Integer courseQuestionCountRedisExpire;

    @Autowired
    private CourseItemBankMapper mapper;

    @Autowired
    private ChapterService chapterService;

    @Autowired
    private ItemBankQuestionRemoteService itemService;

    @Autowired
    private ItemBankTestPaperRemoteService paperService;

    @Autowired
    private RedisConfig redis;

    //region 获取指定题库信息

    /**
     * 根据题库id获取可用题库信息.
     *
     * @param itemBankId 题库id
     * @return 可用题库信息
     */
    @Override
    public CourseItemBank getCourseItemBankInfo(String itemBankId) {
        if (!UUIDUtil.isUUID(itemBankId)) {
            return null;
        }
        return mapper.getEnabledById(itemBankId);
    }

    /**
     * 根据资源课程id获取可用题库信息.
     *
     * @param courseId 资源课程id
     * @return 可用题库信息
     */
    @Override
    public CourseItemBank getCourseItemBankInfoByCourseId(String courseId) {
        if (!UUIDUtil.isUUID(courseId)) {
            return null;
        }
        return mapper.getEnabledByCourseId(courseId);
    }

    /**
     * 根据题库id获取题库信息.
     *
     * @param itemBankId 题库id
     * @return 题库信息 not deleted by id
     */
    @Override
    public CourseItemBank getNotDeletedById(String itemBankId) {
        if (!UUIDUtil.isUUID(itemBankId)) {
            return null;
        }
        return mapper.getNotDeletedById(itemBankId);
    }
    //endregion

    //region 各类是否和存在判断

    /**
     * 判断该课程题库，是否来源于内部.
     *
     * @param itemBankId 题库id
     * @return true，内部课程题库；false，外部课程题库
     */
    @Override
    public boolean isInnerCourse(String itemBankId) {
        if (!UUIDUtil.isUUID(itemBankId)) {
            return false;
        }

        CourseItemBank model = getNotDeletedById(itemBankId);

        return (model != null && model.getSource() == Source.INNER.getIndex());
    }

    /**
     * 根据appKey,机构ID和题库名称，判断是否存在数据
     *
     * @param appKey     appKeyd
     * @param orgid      机构ID
     * @param name       题库名称
     * @param itemBankId 题库ID
     * @return the boolean
     */
    private boolean isExistCourseItemBankForInner(String appKey, String orgid, String name, String itemBankId) {
        if (!UUIDUtil.isUUID(orgid)) {
            return false;
        }

        if (itemBankId.length() > 0 && !UUIDUtil.isUUID(itemBankId)) {
            return false;
        }

        int cnt = mapper.isExistCourseItemBankForInner(appKey, orgid, name, itemBankId);

        return cnt > 0;
    }

    /**
     * 根据appKey,资源课程ID判断是否存在数据.
     *
     * @param appKey   appKey
     * @param courseId 资源课程ID
     * @return the boolean
     */
    private boolean isExistCourseItemBankForOuter(String appKey, String courseId) {
        if (!UUIDUtil.isUUID(courseId)) {
            return false;
        }

        int cnt = mapper.isExistCourseItemBankForOuter(appKey, courseId);

        return cnt > 0;
    }
    //endregion

    //region 新增题库

    //region 新增课程题库

    /**
     * 新增课程题库.
     *
     * @param model    课程题库信息
     * @param isNative 来源：True，内部；False，外部
     * @return the int
     */
    @Override
    public ReturnModel insert(ItemBank model, boolean isNative) {
        ReturnModel returnModel = new ReturnModel();
        int ret;
        model.setCourseID(UUID.randomUUID().toString());
        if (model == null || StringUtil.isEmpty(model.getCourseName()) || StringUtil.isEmpty(model.getAppID()) || !UUIDUtil.isUUID(model.getCourseID())) {
            ret = GlobalConst.DATA_FORMAT_ERROR;
            returnModel.setCode(ret);
            return returnModel;
        }

        String itemBankId = UUID.randomUUID().toString();
        CourseItemBank itemBank = new CourseItemBank();
        itemBank.setItemBankID(itemBankId);
        itemBank.setCourseName(model.getCourseName());
        itemBank.setCourseID(model.getCourseID());
        itemBank.setCreateOrgID(model.getCreateOrgID());
        itemBank.setAppID(model.getAppID());
        itemBank.setCreateTime(DateUtil.getCurrentTimeToShowString());

        ret = insertItemBank(itemBank, isNative);

        if (ret == GlobalConst.SUCCESS) {
            returnModel.setData(itemBankId);
        }

        returnModel.setCode(ret);
        return returnModel;
    }
    //endregion

    //region 课程题库新增

    /**
     * 课程题库新增.
     *
     * @param model    课程题库信息
     * @param isNative 来源：True，内部；False，外部
     * @return the int
     */
    private int insertItemBank(CourseItemBank model, boolean isNative) {
        model.setCreateTime(DateUtil.getCurrentTimeToShowString());
        model.setStatus(YesOrNo.NO.getIndex());
        model.setIsPublic(YesOrNo.NO.getIndex());
        model.setCreateOrgID(StringUtil.isEmpty(model.getCreateOrgID()) ? GlobalConst.EMPTYUUID : model.getCreateOrgID());

        if (isNative) {
            //判断同一appKey的同一机构下课程名称是否重复
            if (isExistCourseItemBankForInner(model.getAppID(), model.getCreateOrgID(), model.getCourseName(), "")) {
                return GlobalConst.COURSE_EXIST;
            }

            model.setSource(Source.INNER.getIndex());
        } else {
            //判断外部情况下，同一appKey下资源课程代码是否重复
            if (isExistCourseItemBankForOuter(model.getAppID(), model.getCourseID())) {
                return GlobalConst.COURSE_EXIST;
            }

            model.setSource(Source.OUTER.getIndex());
        }

        try {
            mapper.insert(model);

            if (isNative) {
                //创建内部课程的根章节
                Chapter chapter = new Chapter();
                chapter.setChapterID(model.getItemBankID());
                chapter.setChapterName(model.getCourseName());
                chapter.setChapterType(ChapterType.COURSE.getIndex());
                chapter.setCourseID(model.getItemBankID());
                chapter.setCreater("");
                chapter.setCreateTime(DateUtil.getCurrentTimeToShowString());
                chapter.setStatus(SysState.START.getIndex());
                chapter.setParentChapterID(chapter.getChapterID());

                if (chapterService.insert(model.getItemBankID(),chapter).getCode() != GlobalConst.SUCCESS) {
                    delete(model.getItemBankID(), model.getAppID());
                    return GlobalConst.DATA_BASE_ERROR;
                }
            }

            return GlobalConst.SUCCESS;
        } catch (Exception e) {
            return GlobalConst.DATA_BASE_ERROR;
        }

    }
    //endregion

    //region 复制课程题库

    /**
     * 复制课程题库.
     *
     * @param sourceCourseId 源资源课程ID（被共享的课程）
     * @param courseModel    复制课程模型
     * @return the return model
     */
    @Override
    public ReturnModel copy(String sourceCourseId, CopyCourseModel courseModel) {
        ReturnModel model = new ReturnModel();

        //除所属机构ID外，其余任何参数缺失均返回错误；
        if (courseModel == null || courseModel.getTargetCourseID().isEmpty()) {
            model.setCode(GlobalConst.INCOMPLETE_DATA);
            model.setMessage("参数缺失");
            return model;
        }

        //判断源资源课程ID在【课程题库信息表】中是否存在，如果不存在则返回错误；
        CourseItemBank sourceItembank = mapper.getEnabledByCourseId(sourceCourseId);
        if (sourceItembank == null) {
            model.setCode(GlobalConst.COURSE_NOT_EXIST);
            model.setMessage("源资源课程不存在对应题库");
            return model;
        }

        //判断目标资源课程ID在【课程题库信息表】中是否存在，如果存在则返回错误；
        if (mapper.getEnabledByCourseId(courseModel.getTargetCourseID()) != null) {
            model.setCode(GlobalConst.COURSE_EXIST);
            model.setMessage("目标资源课程已经存在题库");
            return model;
        }

        //根据目标资源课程ID在【课程题库信息表】中创建题库课程；
        ItemBank itemBank = new ItemBank();
        itemBank.setAppID(courseModel.getAppID());
        itemBank.setCourseID(courseModel.getTargetCourseID());
        itemBank.setCourseName(courseModel.getCourseName());
        itemBank.setCreateOrgID(courseModel.getCreateOrgID());

        //新增题库
        model = insert(itemBank, false);
        //新增题库课程失败
        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        String targetItemBankId = model.getData().toString();

        //共享试题
        model = itemService.shareQuestion(sourceItembank.getItemBankID(), targetItemBankId, itemBank.getAppID(),
                itemBank.getCreateOrgID(), courseModel.getChapterRelation());

        if (model.getCode() != GlobalConst.SUCCESS) {
            //删除课程题库
            delete(targetItemBankId, itemBank.getAppID());

            return model;
        }

        //复制试卷
        Map<String, String> paperResult = paperService.copyCrossItemBank(sourceItembank.getItemBankID(), targetItemBankId,
                itemBank.getCreateOrgID(), courseModel.getTestPaperMap());

        Map<String, Object> result = new HashedMap();
        result.put("id", targetItemBankId);
        result.put("plist", paperResult);

        model.setData(result);
        model.setCode(GlobalConst.SUCCESS);

        return model;
    }
    //endregion

    //endregion

    //region 修改题库

    /**
     * 修改课程题库.
     *
     * @param id   题库id
     * @param name 题库课程名称
     * @return the int
     */
    @Override
    public int update(String id, String name) {
        //判断是否存在
        CourseItemBank itemBank = mapper.getNotDeletedById(id);
        if (itemBank == null) {
            return GlobalConst.COURSE_NOT_EXIST;
        }

        //内部修改时，同一appid下同一Org机构下的题库名称不可以重复
        if (itemBank.getSource() == Source.INNER.getIndex() && isExistCourseItemBankForInner(itemBank.getAppID(), itemBank.getCreateOrgID(), name, id)) {
            return GlobalConst.COURSE_EXIST;
        }

        //记录下来原来名称，防止章节更新失败回滚
        String oldCourseName = itemBank.getCourseName();

        try {
            mapper.update(id, name);
            if (itemBank.getSource() == Source.INNER.getIndex()) {
                Chapter chapter = chapterService.getChapterById(id);
                if (chapter != null && (chapterService.updateChapterName(null,null,id, name)).getCode() != GlobalConst.SUCCESS) {
                    mapper.update(id, oldCourseName);
                    return GlobalConst.DATA_BASE_ERROR;
                }
            }

            return GlobalConst.SUCCESS;
        } catch (Exception e) {
            return GlobalConst.DATA_BASE_ERROR;
        }
    }

    /**
     * 更新题库状态.
     *
     * @param id 题库ID
     * @return the int
     */
    @Override
    public int changeStatus(String id) {
        if (!UUIDUtil.isUUID(id)) {
            return GlobalConst.INCOMPLETE_DATA;
        }

        //判断是否存在
        CourseItemBank itemBank = mapper.getNotDeletedById(id);
        if (itemBank == null) {
            return GlobalConst.COURSE_NOT_EXIST;
        }

        int oldStatus = itemBank.getStatus();

        int newStatus = (oldStatus == SysState.STOP.getIndex()) ? SysState.START.getIndex() : SysState.STOP.getIndex();

        try {
            mapper.changeStatus(id, newStatus);
            return GlobalConst.SUCCESS;
        } catch (Exception e) {
            return GlobalConst.DATA_BASE_ERROR;
        }
    }
    //endregion

    //region 删除题库

    /**
     * 删除课程题库(外部不允许通过此接口删除).
     *
     * @param itemBankId 题库id
     * @param appKey     appKey
     * @return the int
     */
    @Override
    public int delete(String itemBankId, String appKey) {
        if (StringUtil.isEmpty(appKey) || !UUIDUtil.isUUID(itemBankId)) {
            return GlobalConst.INCOMPLETE_DATA;
        }

        CourseItemBank itemBank = mapper.getNotDeletedById(itemBankId);
        if (itemBank == null) {
            return GlobalConst.COURSE_NOT_EXIST;
        }

        //校验权限，头信息appid和题库所属app必须一致
        if (!itemBank.getAppID().equalsIgnoreCase(appKey)) {
            return GlobalConst.NO_PERMISSION;
        }

        try {
            //如果课程存在自定义题型，试题，试卷，策略均无法删除(不判断章节)
            if (mapper.getQuestionTypeCountByItemBankId(itemBankId) > 0 ||
                    mapper.getQuestionCountByItemBankId(itemBankId) > 0 ||
                    mapper.getTestPaperCountByItemBankId(itemBankId) > 0 ||
                    mapper.getRulesCountByItemBankId(itemBankId) > 0 ||
                    mapper.getChapterByItemBankId(itemBankId) > 0) {
                return GlobalConst.DATA_EXIST;
            }
            //删除课程全部章节
            chapterService.deleteByItemBankId(itemBankId);
            //删除题库课程
            mapper.delete(itemBankId);

            return GlobalConst.SUCCESS;
        } catch (Exception e) {
            return GlobalConst.DATA_BASE_ERROR;
        }
    }
    //endregion

    //region 权限检查

    /**
     * 判断给定appkey是否包含在配置文件的applist许可列表内，如果包含则说明拥有删除题库权的权利.
     *
     * @param appKey appKey
     * @return true，拥有；false，不拥有
     */
    @Override
    public boolean hasSuperPermission(String appKey) {
        if (StringUtil.isEmpty(appKey)) {
            return false;
        }
        String[] apps = permissionList.split(",");
        for (String app : apps) {
            if (app.equalsIgnoreCase(appKey)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断给定的appkey是否拥有给定的资源课程id的管理权限
     *
     * @param courseID 资源id
     * @param appKey   appkey
     * @return true，拥有；false，不拥有
     */
    @Override
    public boolean coursePermission(String courseID, String appKey) {
        CourseItemBank itemBank = getCourseItemBankInfoByCourseId(courseID);

        return (itemBank != null && (hasSuperPermission(appKey) || itemBank.getAppID().equalsIgnoreCase(appKey)));
    }


    /**
     * 判断给定的appkey是否拥有给定的题库id的管理权限，如果是题库所有者或者拥有超级权限均视为拥有权限.
     *
     * @param itemBankId 题库id
     * @param appKey     appkey
     * @return true，拥有；false，不拥有
     */
    @Override
    public boolean hasPermission(String itemBankId, String appKey) {
        CourseItemBank itemBank = getCourseItemBankInfo(itemBankId);

        return (itemBank != null && (hasSuperPermission(appKey) || itemBank.getAppID().equalsIgnoreCase(appKey)));
    }

    //endregion

    // region 题量统计

    /**
     * Redis 查询题数集合
     *
     * @return
     */
    @Override
    public ReturnModel findCourseQuestionCount() {
        ReturnModel returnModel = new ReturnModel();
        Map<String, Integer> map = new HashMap<>();
        Set<String> keys = redis.getKeys(courseQuestionCountKey + ":*");
        Iterator<String> iterator = keys.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String value = redis.get(key);
            map.put(key.split(":")[1], Integer.valueOf(value));
        }
        returnModel.setData(map);
        return returnModel;
    }

    /**
     * Redis 题数集合添加到redis
     */
    @Override
    public void addCourseQuestionCount() {
        List<QuestionCountModel> questionCounts = mapper.findQuestionCount();
        if (!questionCounts.isEmpty()) {
            for (QuestionCountModel questionCountModel : questionCounts) {
                /**
                 * 存redis
                 * Redis Key Format	 ItembankQuestionCount:CourseID
                 * Redis Value	Number
                 *  默认存储 24小时
                 */
                redis.set(courseQuestionCountKey + ":" + questionCountModel.getCourseID(), questionCountModel.getQuestionCount(), courseQuestionCountRedisExpire);
            }
        }
    }

    //endregion
}
